/***************************************************************************
 *   Copyleft 2008-2009 by												   *
 *	 Iwanicki Krzysztof													   *
 *   <gamma.mini.pw.edu.pl/~iwanickik>									   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 ***************************************************************************/
#ifndef __VXMLINPUTSTREAM_H__
#define __VXMLINPUTSTREAM_H__

#include "./vInputStream.h"
#include "./TinyXML/tinyxml.h"
#include "../../Macros/vMemoryMacros.h"

namespace Vendetta {
	/*! \class vXmlInputStream
	 *   \brief A vXmlInputStream abstract class manages loading data from xml files.
	 *
	 *	vXmlInputStream use TinyXML parser for parsing .xml files. 
	 *	TinyXML can be found at http://www.grinninglizard.com/tinyxml
	 *
	 *	\sa TinyXML.
	 */
	class vXmlInputStream: public vInputStream {
	public:
		/*! \brief Default constructor.
		 *
		 */	
		vXmlInputStream() { }

		/*! \brief Destructor.
		 *
		 */	
		virtual ~vXmlInputStream() { }


		/*! \brief Loads data from xml file. Implemented from vInputStream.
		 *
		 *	Calls init to prepare data for saving on hard drive. All data operations after
		 *	loading file should be made in postLoad method.
		 *			 
		 *  \param		fileName			File name in which data should be serialized.
		 *	\return							True if data was successfully saved, false otherwise.
		 *	\sa	TinyXML.
		 *	\sa	vXmlInputStream::postLoad.
		 *	\sa vInputStream.
		 */
		virtual vBool LoadFromFile(const vString& fileName);

	protected:
		/*! \brief Pure virtual method. Is called after file is loaded.
		 *
		 *	\return							True if data was successfully loaded, false otherwise.
		 *
		 */
		virtual vBool postLoad() = 0;

		/*! \brief Reads attribute with given name as vInt.
		 *
		 *	\param		attName				Attribute name.
		 *	\return							Attribute value as vInt.
		 *	\exception	vException			Thrown when attribute does not exist or is not vInt.
		 *	\sa			vString.
		 */
		vInt attributeInt(const vString& attrName);

		/*! \brief Reads attribute with given name as vReal.
		 *
		 *	\param		attName				Attribute name.
		 *	\return							Attribute value as vReal.
		 *	\exception	vException			Thrown when attribute does not exist or is not vReal.
		 *	\sa			vString.
		 */
		vReal attributeReal(const vString& attrName);

		/*! \brief Reads attribute with given name as vBool.
		 *
		 *	\param		attName				Attribute name.
		 *	\return							Attribute value as vBool.
		 *	\exception	vException			Thrown when attribute does not exist or is not vBool.
		 *	\sa			vString.
		 */
		vBool attributeBool(const vString& attrName);

		/*! \brief Reads attribute with given name as vUInt.
		 *
		 *	\param		attName				Attribute name.
		 *	\return							Attribute value as vUInt.
		 *	\exception	vException			Thrown when attribute does not exist or is not vUInt.
		 *	\sa			vString.
		 */
		vUInt attributeUInt(const vString& attrName);

		/*! \brief Reads attribute with given name as vUInt32.
		 *
		 *	\param		attName				Attribute name.
		 *	\return							Attribute value as vUInt32.
		 *	\exception	vException			Thrown when attribute does not exist or is not vUInt32.
		 *	\sa			vString.
		 */
		vUInt32 attributeUInt32(const vString& attrName);

		/*! \brief Reads attribute with given name as vLong.
		 *
		 *	\param		attName				Attribute name.
		 *	\return							Attribute value as vLong.
		 *	\exception	vException			Thrown when attribute does not exist or is not vLong.
		 *	\sa			vString.
		 */
		vLong attributeLong(const vString& attrName);

		/*! \brief Reads attribute with given name as vReal.
		 *
		 *	\param		attName				Attribute name.
		 *	\return							Attribute value as vString.
		 *	\exception	vException			Thrown when attribute does not exist.
		 *	\sa			vString.
		 */
		vString attributeString(const vString& attrName);

		/*! \brief Reads text tag.
		 *
		 *	If parameter is not specified then it use current tag as text tag.
		 *	If parameter is specified then it checks for children with given name
		 *	of current tag.
		 *
		 *	\param		tagName				Text tag name.
		 *	\return							Text value of text tag.
		 *	\exception	vException			Thrown when tag does not exist in current path.
		 *	\sa			vString.
		 */
		vString textTag(const vString& tagName = "");

		/*! \brief Returns current tag name.
		 *
		 *	If there is no tag in current path returns empty string.
		 *
		 *	\return							Current tag name.
		 *	\sa			vString.
		 */
		vString tagName();

		/*! \brief Opens tag with given name.
		 *
		 *	Opened tag is the current tag to work on. When finished defining new tag,
		 *	use closeLastOpenedTagForWrite to close all tags and clean memory.
		 *
		 *	\param		tagName				Tag name.
		 *	\sa			vXmlInputStream::closeLastOpenedTagForWrite.
		 */
		vVoid openTagForRead(const vString& path);

		/*! \brief Closes last opened tag for read. 
		 *		
		 *	To go back to parent tag in tree, this method must be called to close current
		 *	tag we are working on.
		 *	
		 */	
		vVoid closeLastOpenTagForRead();

		/*! \brief Closes all opened tag for read. 
		*	
		*/	
		vVoid closeAllOpenTagsForRead();

		/*! \brief Iterates through child tags.
		 *
		 *	It it used to start iterating through current tag child tags. If children don't 
		 *	exists it will return false, otherwise true. To start using child element we must
		 *	call nextChildTag() to set child tag as current element.
		 *	
		 *	\return							True if there is at least one child, false otherwise.
		 *	\sa			vXmlInputStream::nextChildTag.
		 */	
		vBool iterateChildTags();

		/*! \brief Sets current element child tag active.
		 *
		 *	First must be called iterateChildTags() to check if there are children
		 *	and init iteration process.
		 *	
		 *	\return							True if there is next child, false otherwise.
		 *	\sa			vXmlInputStream::iterateChildTags.
		 */	
		vBool nextChildTag();

		/*! \brief Iterates through sibling tags.
		*
		*	It it used to start iterating through current tag sibling tags. If siblings don't 
		*	exists it will return false, otherwise true. To start using sibling element we must
		*	call nextSiblingTag() to set sibling tag as current element.
		*	
		*	\return							True if there is at least one child, false otherwise.
		*	\sa			vXmlInputStream::nextSiblingTag.
		*/
		vBool iterateSiblingTags();

		/*! \brief Sets current element sibling tag active.
		*
		*	First must be called iterateChildTags() to check if there are siblings
		*	and init iteration process.
		*	
		*	\return							True if there is next sibling, false otherwise.
		*	\sa			iterateSiblingTags::nextSiblingTag.
		*/	
		vBool nextSiblingTag();

	private:
		vVoid traversePath(const vString& path);

		TiXmlElement* rootTag(const vString& rootTag);

		TiXmlElement* openParentTag(TiXmlElement* pElem);

		TiXmlElement* openChildTag(TiXmlElement* pParent, const vString& childName);

	protected:
		TiXmlDocument mDocTag;

	private:
		vStack<TiXmlElement*> mTags;
	};
}

#endif // __VXMLINPUTSTREAM_H__